#ifndef PW_PBL_COMMON_HPP
#define PW_PBL_COMMON_HPP

#include <array>
#include "Concepts/Core.hpp"
#include "IntFor.hpp"

namespace pw_pbl
{
	template <typename T>
	inline bool memory_equal(const T &left, const T &right)
	{
		using type = std::array<UIntFor::Size<alignof(T)>, sizeof(T) / alignof(T)>;
		return reinterpret_cast<const type &>(left) == reinterpret_cast<const type &>(right);
	}

	template <typename T>
	inline bool memory_not_equal(const T &left, const T &right)
	{
		using type = std::array<UIntFor::Size<alignof(T)>, sizeof(T) / alignof(T)>;
		return reinterpret_cast<const type &>(left) != reinterpret_cast<const type &>(right);
	}

	template <typename T>
	struct ArrayBegin
	{
		T *ptr;

		constexpr ArrayBegin(std::nullptr_t) noexcept : ptr(nullptr) {}

		constexpr ArrayBegin(std::initializer_list<T> ary) noexcept : ptr(ary.begin()) {}

		constexpr ArrayBegin(T (&ary)[]) noexcept : ptr(&ary[0]) {}

		template <size_t N>
		constexpr ArrayBegin(T (&ary)[N]) noexcept : ptr(&ary[0]) {}

		template <size_t N>
		constexpr ArrayBegin(std::array<T, N> &ary) noexcept : ptr(ary.begin()) {}

		template <size_t N> requires std::is_const_v<T>
		constexpr ArrayBegin(const std::array<std::remove_const_t<T>, N> &ary) noexcept : ptr(ary.begin()) {}

		explicit constexpr ArrayBegin(T &obj) noexcept : ptr(&obj) {}

		explicit constexpr ArrayBegin(T *obj) noexcept : ptr(obj) {}

		constexpr operator T *() const { return ptr; }

		template <typename Self>
		constexpr decltype(auto) raw(this Self &&self)
		{
			if constexpr (ccIsTemplate<T, ArrayBegin>)
				return &std::forward_like<Self>(self.ptr)->raw();
			else
				return std::forward_like<Self>(self.ptr);
		}
	};
} // namespace pw_pbl

#endif // PW_PBL_COMMONMACRO_HPP
